/**
 * Copies all the properties of config to obj.
 * @param {Object} obj The receiver of the properties
 * @param {Object} config The source of the properties
 * @param {Object} defaults A different object that will also be applied for default values
 * @return {Object} returns obj
 * @member Cmspad apply
 */
cmspad.apply = function(o, c, d){
	if (d) {
		// no 'this' reference for friendly out of scope calls
		cmspad.apply(o, d);
	}
	if (o && c && typeof c == 'object') {
		for (var p in c) {
			o[p] = c[p];
		}
	}
	return o;
};

cmspad.apply(cmspad, {
	
	nls:{
		STATUS_CODE: 'HTTP Status Code: ',
		ERROR_MESSAGE: 'Error Message: '
	},
	
	/**
	 * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
	 * <pre><code>
	 cmspad.namespace('Company', 'Company.data');
	 Company.Widget = function() { ... }
	 Company.data.CustomStore = function(config) { ... }
	 </code></pre>
	 * @param {String} namespace1
	 * @param {String} namespace2
	 * @param {String} etc
	 * @method namespace
	 */
	namespace: function(){
		var a = arguments, o = null, i, j, d, rt;
		for (i = 0; i < a.length; ++i) {
			d = a[i].split('.');
			rt = d[0];
			eval('if (typeof ' + rt + ' == \'undefined\'){' + rt + ' = {};} o = ' + rt + ';');
			for (j = 1; j < d.length; ++j) {
				o[d[j]] = o[d[j]] ||
				{};
				o = o[d[j]];
			}
		}
	},
	
	/**
	 * Extends one class with another class and optionally overrides members with the passed literal. This class
	 * also adds the function "override()" to the class that can be used to override
	 * members on an instance.
	 * @param {Object} subclass The class inheriting the functionality
	 * @param {Object} superclass The class being extended
	 * @param {Object} overrides (optional) A literal with members
	 * @method extend
	 */
	extend: function(){
		var io = function(o){
			for (var m in o) {
				this[m] = o[m];
			}
		};
		return function(sb, sp, overrides){
			if (typeof sp == 'object') {
				overrides = sp;
				sp = sb;
				sb = function(){
					sp.apply(this, arguments);
				};
			}
			var F = function(){
			}, sbp, spp = sp.prototype;
			F.prototype = spp;
			sbp = sb.prototype = new F();
			sbp.constructor = sb;
			sb.superclass = spp;
			if (spp.constructor == Object.prototype.constructor) {
				spp.constructor = sp;
			}
			sb.override = function(o){
				cmspad.override(sb, o);
			};
			sbp.override = io;
			cmspad.override(sb, overrides);
			return sb;
		};
	}(),

	/**
	 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
	 * Usage:<pre><code>
	 cmspad.override(MyClass, {
	 newMethod1: function(){
	 // etc.
	 },
	 newMethod2: function(foo){
	 // etc.
	 }
	 });
	 </code></pre>
	 * @param {Object} origclass The class to override
	 * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
	 * containing one or more methods.
	 * @method override
	 */
	override: function(origclass, overrides){
		if (overrides) {
			var p = origclass.prototype;
			for (var method in overrides) {
				p[method] = overrides[method];
			}
		}
	},
	
	$: function(sId){
		if (!sId) {
			return null;
		}
		if(sId instanceof Object){
			return sId;
		}
		var obj = document.getElementById(sId);
		if (!obj && document.all) {
			obj = document.all[sId];
		}
		return obj;
	},
	
	////////////////////////////// Cookie Functions //////////////////////////////
	
	setCookie: function(name, value){
		var expdate = new Date();
		var argv = arguments;
		var argc = arguments.length;
		var expires = (argc > 2) ? argv[2] : null;
		var path = (argc > 3) ? argv[3] : null;
		var domain = (argc > 4) ? argv[4] : null;
		var secure = (argc > 5) ? argv[5] : false;
		if (expires != null) {
			expdate.setTime(expdate.getTime() + (expires * 1000));
		}
		document.cookie = name + '=' + escape(value) + ((expires == null) ? '' : ('; expires=' + expdate.toGMTString())) + ((path == null) ? '' : ('; path=' + path)) + ((domain == null) ? '' : ('; domain=' + domain)) + ((secure == true) ? '; secure' : '');
	},
	
	delCookie: function(name){
		var exp = new Date();
		exp.setTime(exp.getTime() - 1);
		var cval = this.getCookie(name);
		document.cookie = name + '=' + cval + '; expires=' + exp.toGMTString();
	},
	
	getCookie: function(name){
		var arg = name + '=';
		var alen = arg.length;
		var clen = document.cookie.length;
		var i = 0;
		while (i < clen) {
			var j = i + alen;
			if (document.cookie.substring(i, j) == arg) {
				return this._getCookieVal(j);
			}
			i = document.cookie.indexOf(' ', i) + 1;
			if (i == 0) {
				break;
			}
		}
		return null;
	},
	
	_getCookieVal: function(offset){
		var endstr = document.cookie.indexOf(';', offset);
		if (endstr == -1) {
			endstr = document.cookie.length;
		}
		return unescape(document.cookie.substring(offset, endstr));
	},
	
	/////////////////////////////////// DOM Functions ////////////////////////////////
	
	includeScript: function(sFileName, id){
		var objHead = document.getElementsByTagName('head');
		var objScript = document.createElement('script');
		objScript.type = 'text/javascript';
		objScript.src = sFileName;
		if(id){
			objScript.id = id;
		}
		objHead[0].appendChild(objScript);
		objScript.onError = function(e){
			objHead[0].removeChild(objScript);
		};
		return objScript;
	},
	
	includeStyle: function(sFileName, id){
		var objHead = document.getElementsByTagName('head');
		var objStyle = document.createElement('link');
		objStyle.type = 'text/css';
		objStyle.rel = 'stylesheet';
		objStyle.href = sFileName;
		if(id){
			objStyle.id = id;
		}
		objHead[0].appendChild(objStyle);
		objStyle.onError = function(e){
			objHead[0].removeChild(objStyle);
		};
		return objStyle;
	},
	
	create: function(sParentId, sTag, sId){
		var objParent = this.$(sParentId);
		objElement = document.createElement(sTag);
		objElement.setAttribute('id', sId);
		if (objParent) {
			objParent.appendChild(objElement);
		}
	},
	
	remove: function(sId){
		objElement = this.$(sId);
		if (objElement && objElement.parentNode && objElement.parentNode.removeChild) {
			objElement.parentNode.removeChild(objElement);
		}
	},
	
	replace: function(sId, sAttribute, sSearch, sReplace){
		var bFunction = false;
		if (sAttribute == 'innerHTML') {
			sSearch = this.getBrowserHTML(sSearch);
		}
		eval('var txt=this.$(\'' + sId + '\').' + sAttribute);
		if (typeof txt == 'function') {
			txt = txt.toString();
			bFunction = true;
		}
		if (txt.indexOf(sSearch) > -1) {
			var newTxt = '';
			while (txt.indexOf(sSearch) > -1) {
				x = txt.indexOf(sSearch) + sSearch.length + 1;
				newTxt += txt.substr(0, x).replace(sSearch, sReplace);
				txt = txt.substr(x, txt.length - x);
			}
			newTxt += txt;
			if (bFunction || this._willChange(sId, sAttribute, newTxt)) {
				if (this.isIE || sAttribute != 'bind' || bFunction) {
					eval('this.$(\'' + sId + '\').' + sAttribute + '=newTxt;');
				} else {
					eval('this.$(\'' + sId + '\').setAttribute(\'' + sAttribute + '\',newTxt);');
				}
			}
		}
	},
	
	style: function(id, property, data){
		eval('this.$(\'' + id + '\').style.' + property + '=\'' + data + '\';');
	},
	
	defer: function(script, interval, loop){
		if(typeof script == Function){
			func = script;
		}else{
			func = function(){ eval(script); };
		}
		if(loop == '1'){
			setInterval(func, interval);
		}else{
			setTimeout(func, interval);
		}
	},
	
	dialog: function(url, width, height, resizable, scrollbars){
		x = parseInt(screen.width / 2.0) - (width / 2.0);
		y = parseInt(screen.height / 2.0) - (height / 2.0);
		if (window.addEventListener) {
			sFeatures = 'top=' + y + ',left=' + x + ',width=' + width + ',height=' + height + ',modal=yes,z-look=yes,status=no,dialog=yes,resizable=' + resizable + ',scrollbars=' + scrollbars;
			var win = window.open(url, 'cmspad_dialog', sFeatures);
			eval('try{win.resizeTo(width,height);}catch(e){}');
			win.opener.addEventListener('focus', function(){
				setTimeout(function(){
					win.opener.blur();
					win.focus();
				}, 0);
			}, false);
			return win;
		} else {
			sFeatures = 'dialogWidth:' + width + 'px;dialogHeight:' + height + 'px;dialogLeft:' + x + 'px;dialogTop:' + y + 'px;resizable:' + resizable + ';scroll:' + scrollbars + ';status:no;help:no;';
			return window.showModalDialog(url, null, sFeatures);
		}
	},
	
	insertBefore: function(sBeforeId, sTag, sId){
		var objSibling = this.$(sBeforeId);
		objElement = document.createElement(sTag);
		objElement.setAttribute('id', sId);
		objSibling.parentNode.insertBefore(objElement, objSibling);
	},
	
	insertAfter: function(sAfterId, sTag, sId){
		var objSibling = this.$(sAfterId);
		objElement = document.createElement(sTag);
		objElement.setAttribute('id', sId);
		objSibling.parentNode.insertBefore(objElement, objSibling.nextSibling);
	},
	
	getInput: function(sType, sName, sId){
		var Obj;
		if (!window.addEventListener) {
			Obj = document.createElement('<input type=\'' + sType + '\' id=\'' + sId + '\' name=\'' + sName + '\'>');
		} else {
			Obj = document.createElement('input');
			Obj.setAttribute('type', sType);
			Obj.setAttribute('name', sName);
			Obj.setAttribute('id', sId);
		}
		return Obj;
	},
	
	createInput: function(sParentId, sType, sName, sId){
		var objParent = this.$(sParentId);
		var objElement = this.getInput(sType, sName, sId);
		if (objParent && objElement) {
			objParent.appendChild(objElement);
		}
	},
	
	insertInputBefore: function(sBeforeId, sType, sName, sId){
		var objSibling = this.$(sBeforeId);
		var objElement = this.getInput(sType, sName, sId);
		if (objElement && objSibling && objSibling.parentNode) {
			objSibling.parentNode.insertBefore(objElement, objSibling);
		}
	},
	
	insertInputAfter: function(sAfterId, sType, sName, sId){
		var objSibling = this.$(sAfterId);
		var objElement = this.getInput(sType, sName, sId);
		if (objElement && objSibling && objSibling.parentNode) {
			objSibling.parentNode.insertBefore(objElement, objSibling.nextSibling);
		}
	},
	
	createFrame: function(name, id, src){
		var iframe;
		if (!id) {
			id = '';
		}
		if (!window.addEventListener) {
			iframe = document.createElement('<iframe id=\'' + id + '\' name=\'' + name + '\'>');
		} else {
			iframe = document.createElement('iframe');
			iframe.id = id;
			iframe.name = name;
		}
		iframe.width = '0';
		iframe.height = '0';
		iframe.style.display = 'none';
		iframe.scrolling = 'no';
		iframe.src = src;
		document.body.appendChild(iframe);
		return iframe;
	},
	
	addEvent: function( obj, type, fn ) {
		var obj = ( obj.constructor === String ) ? document.getElementById( obj ) : obj;
		if ( obj.attachEvent ) {
			obj[ 'e' + type + fn ] = fn;
			obj[ type + fn ] = function(){ obj[ 'e' + type + fn ]( window.event ) };
			obj.attachEvent( 'on' + type, obj[ type + fn ] );
		} else obj.addEventListener( type, fn, false );
	},
	
  removeEvent: function( obj, type, fn ) {
		var obj = ( obj.constructor === String ) ? document.getElementById( obj ) : obj;
		if ( obj.detachEvent ) {
			obj.detachEvent( 'on' + type, obj[ type + fn ] );
			obj[ type + fn ] = null;
		 } else obj.removeEventListener( type, fn, false );
	},

	////////////////////////////////// RPC Functions ////////////////////////////////
	
	json: function(e, c){
		var postData = cmspad.core.getBindData('json', e);
		if (postData) {
			cmspad.ajax.post(this.REQUEST_URI, {
				success: function(r){
					if(r.responseText){
						var data;
						if(cmspad.security.decrypt){
							data = cmspad.security.decrypt(r.responseText, cmspad.SECURITY_KEY);
						}else{
							data = r.responseText;
						}
						var jsonObj = eval('(' + data + ')');
						c(jsonObj);
					}else{
						c(null);
					}
				},
				failure: function(r){
					var errorString = this.nls.STATUS_CODE + r.status;
					errorString += this.nls.ERROR_MESSAGE + r.statusText;
					cmspad.console.error(errorString);
				}
			}, postData);
			return true;
		}
		return false;
	},
	
	call: function(e){
		v = cmspad.core.getExprData(e);
		if (v) {
			cmspad_call(v.portlet, v.method, v.arguments);
			return true;
		}
		return false;
	}
});

cmspad.namespace('cmspad', 'cmspad.ajax', 'cmspad.core', 'cmspad.validator', 'cmspad.security', 'cmspad.console');
